﻿using System.Linq;
using System.Web;

namespace ezCloud.Api.Common
{
    using System;
    using System.Net.Http;
    using ezCloud.Data;
    using Microsoft.AspNet.Identity;
    using Properties;
    using System.Collections.Generic;

    public class UserSessionManager
    {
        public static List<UserSessions> _allSession = null;
        protected ezCloudDataContext Data { get; private set; }

        public UserSessionManager(ezCloudDataContext data)
        {
            this.Data = data;
            InitUserSession();
        }
        public void InitUserSession()
        {
            if (_allSession == null)
            {
                DeleteExpiredSessions();
                //initialize user session store

                _allSession = this.Data.UserSessions.ToList();

            }
        }
        public UserSessionManager()
            : this(new ezCloudDataContext())
        {
            
        }

        private HttpRequestMessage CurrentRequest
        {
            get
            {
                return (HttpRequestMessage)HttpContext.Current.Items["MS_HttpRequestMessage"];
            }
        }

        /// <returns>The current bearer authorization token from the HTTP headers</returns>
        private string GetCurrentBearerAuthrorizationToken()
        {
            string authToken = null;
            if (CurrentRequest.Headers.Authorization != null)
            {
                if (CurrentRequest.Headers.Authorization.Scheme == "Bearer")
                {
                    authToken = CurrentRequest.Headers.Authorization.Parameter;
                }
            }
            return authToken;
        }

        public string GetCurrentUserId()
        {
            if (HttpContext.Current.User == null)
            {
                return null;
            }
            string userId = HttpContext.Current.User.Identity.GetUserId();
            return userId;
        }
        public void SignOutUserId(string userId)
        {
            InitUserSession();
            Data.ExecuteCommand("Delete From UserSessions Where OwnerUserid='" + userId + "'");
            _allSession.RemoveAll(u => u.OwnerUserId == userId);
        }
        /// <summary>
        /// Extends the validity period of the current user's session in the database.
        /// This will configure the user's bearer authorization token to expire after
        /// certain period of time (e.g. 30 minutes, see UserSessionTimeout in Web.config)
        /// </summary>
        public void CreateUserSession(string username, string authToken)
        {
            InitUserSession();
            var userId = this.Data.AspNetUsers.First(u => u.UserName == username).Id;
            /*Data.ExecuteCommand("Delete From UserSessions Where OwnerUserid='" + userId + "'");
            _allSession.RemoveAll(u => u.OwnerUserId == userId);*/
            var userSession = new UserSessions()
            {
                OwnerUserId = userId,
                AuthToken = authToken,
                ExpirationDateTime = DateTime.Now + Settings.Default.UserSessionTimeout
            };
            this.Data.UserSessions.InsertOnSubmit(userSession);
            // Extend the lifetime of the current user's session: current moment + fixed timeout
            
            this.Data.SubmitChanges();
            _allSession.Add(userSession);
        }

       /* public void CreateUserSession(string username)
        {
            string authToken = GetCurrentBearerAuthrorizationToken();
            var userId = this.Data.AspNetUsers.First(u => u.UserName == username).Id;
            var userSession = new UserSessions()
            {
                OwnerUserId = userId,
                AuthToken = authToken,
                ExpirationDateTime = DateTime.Now + Settings.Default.UserSessionTimeout
            };
            this.Data.UserSessions.InsertOnSubmit(userSession);

            // Extend the lifetime of the current user's session: current moment + fixed timeout
            
            this.Data.SubmitChanges();
            _allSession.Add(userSession);
        }*/
        /// <summary>
        /// Makes the current user session invalid (deletes the session token from the user sessions).
        /// The goal is to revoke any further access with the same authorization bearer token.
        /// Typically this method is called at "logout".
        /// </summary>
        public void InvalidateUserSession()
        {
            string authToken = GetCurrentBearerAuthrorizationToken();
            var currentUserId = GetCurrentUserId();
            InitUserSession();
            var userSession = _allSession.FirstOrDefault(session =>
                session.AuthToken == authToken && session.OwnerUserId == currentUserId);/*this.Data.UserSessions.FirstOrDefault(session =>
                session.AuthToken == authToken && session.OwnerUserId == currentUserId);*/
            if (userSession != null)
            {
                _allSession.Remove(userSession);
                this.Data.UserSessions.Delete(userSession.UserSessionId);
                this.Data.SubmitChanges();            
            }
        }
        public void InvalidateUserSession(string authToken)
        {         
            var currentUserId = GetCurrentUserId();
            var userSession = _allSession.FirstOrDefault(session =>
                session.AuthToken == authToken && session.OwnerUserId == currentUserId);/*this.Data.UserSessions.FirstOrDefault(session =>
                session.AuthToken == authToken && session.OwnerUserId == currentUserId);*/
            if (userSession != null)
            {
                _allSession.Remove(userSession);
                this.Data.UserSessions.Delete(userSession.UserSessionId);
                this.Data.SubmitChanges();
            }
        }

        public static int OnlineSessions()
        {
            
            return _allSession.Where(s => s.ExpirationDateTime > DateTime.Now ).Count();
        }

        /// <summary>
        /// Re-validates the user session. Usually called at each authorization request.
        /// If the session is not expired, extends it lifetime and returns true.
        /// If the session is expired or does not exist, return false.
        /// </summary>
        /// <returns>true if the session is valid</returns>
        public bool ReValidateSession()
        {
            string authToken = this.GetCurrentBearerAuthrorizationToken();
            var currentUserId = this.GetCurrentUserId();
            InitUserSession();
            var userSession = _allSession.FirstOrDefault(session =>
                session.AuthToken == authToken && session.OwnerUserId == currentUserId);
            
            /*var userSession = this.Data.UserSessions.FirstOrDefault(session =>
                session.AuthToken == authToken && session.OwnerUserId == currentUserId);*/

            if (userSession == null)
            {
                // User does not have a session with this token --> invalid session
                return false;
            }

            if (userSession.ExpirationDateTime < DateTime.Now)
            {
                // User's session is expired --> invalid session
                return false;
            }

            // Extend the lifetime of the current user's session: current moment + fixed timeout
            //userSession.ExpirationDateTime = DateTime.Now + Settings.Default.UserSessionTimeout;
            //this.Data.SubmitChanges();

            return true;
        }

        public void DeleteExpiredSessions()
        {
            if (this.Data == null)
                this.Data = new ezCloudDataContext();
            /*var userSession = this.Data.UserSessions.Where(
                session => session.ExpirationDateTime < DateTime.Now);
            this.Data.UserSessions.DeleteAllOnSubmit(userSession);*/
            this.Data.ExecuteCommand("Delete From UserSessions Where ExpirationDateTime<getdate()");
        }
    }
}